

# 一个用中国市场日数据构建技术指标交易策略的实例

# 首先我们自定义了一些技术指标函数

 MA <- function(ret, nvola)
    {
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola) {
     return(vola.company)
     }
      for(j in 1:(length.company - nvola + 1)) 
     {
      vola.j = ret[j:(j + nvola - 1)]
      vola.company[j + nvola - 1] = mean(vola.j)
     } 
      return(vola.company)
    }

  Volatility <- function(ret, nvola)
    {
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola) {
     return(vola.company)
     }
      for(j in 1:(length.company - nvola + 1)) 
     {
      vola.j = ret[j:(j + nvola - 1)]
      vola.company[j + nvola - 1] = sd(vola.j)
     } 
      return(vola.company)
    }


RSI <- function(closeprice,nRSIperiod)  # this function return RSI for input of stock price

{
   
length.company=length(closeprice)

gainloss.company=diff(closeprice)
RSI.company=rep(-1,length.company)
   if(length.company<=nRSIperiod) {return(RSI.company)}
for(j in 1:(length.company-nRSIperiod))
{
gainloss.j=gainloss.company[j:(j+nRSIperiod-1)]
gain.j=gainloss.j[gainloss.j>=0]
             loss.j=gainloss.j[gainloss.j<0]
avegain.j=sum(gain.j)/nRSIperiod
aveloss.j=sum(loss.j)/nRSIperiod
RSI.company[j+nRSIperiod]=100-100/(1+avegain.j/abs(aveloss.j))
}

  return(RSI.company)

}



EMA <- function(ret, nvola)
    {
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola) {
     return(vola.company)
     }

      beta = 2/(nvola+1)
      vola.company[1] = ret[1]
      for(j in 2:length.company ) 
     {
       vola.company[j] = beta*(ret[j] - vola.company[j-1]) + vola.company[j-1]
     } 
      return(vola.company)
    }


  MTM <- function(ret, nvola)
    {
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola) {
     return(vola.company)
     }
      for(j in 1:(length.company - nvola + 1)) 
     {
      vola.j = ret[j:(j + nvola - 1)]
      vola.company[j + nvola - 1] = sum(diff(vola.j))
     } 
      return(vola.company)
    }

  RSV <- function(close,high,low,nvola)
    {
     length.company = length(close)
     vola.company = rep(-1, length.company)
     if(length.company < nvola)
     {
     return(vola.company)
     }
      for(j in nvola:length.company ) 
     {
       vola.company[j] = (close[j] - min(low[(j-nvola+1):j]))/(max(high[(j-nvola+1):j]) - min(low[(j-nvola+1):j]))*100
     } 
      return(vola.company)
    }

   KD <- function(ret,nvola)
    {
      
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola)
     {
     return(vola.company)
     }
      vola.company[1] = ret[1]
      for(j in 2:length.company)
      {
       vola.company[j] = ( ret[j] + vola.company[j-1]*(nvola-1) )/nvola
      }

      return(vola.company)

    }

   ROC <- function(ret, nvola)
    {
     length.company = length(ret)
     vola.company = rep(-1, length.company)
     if(length.company < nvola) {
     return(vola.company)
     }
     for(j in 1:(length.company - nvola + 1)) 
      {
      vola.j = ret[j:(j + nvola - 1)]
      vola.company[j + nvola - 1] = (vola.j[length(vola.j)] - min(vola.j))/(max(vola.j)-min(vola.j))*100
      } 
      return(vola.company)
    }


  LineUp3 <- function(ret)
    {

     length.company = length(ret)
     vola.company = rep(0, length.company)
      
      for(j in 4:length.company)
      {
       if( ret[j] > ret[j-1] & ret[j-1] > ret[j-2] & ret[j-2] > ret[j-3] ) vola.company[j] = 1
      }

      return(vola.company)

    }

  LineDown3 <- function(ret)
    {

     length.company = length(ret)
     vola.company = rep(0, length.company)
      
      for(j in 4:length.company)
      {
       if( ret[j] < ret[j-1] & ret[j-1] < ret[j-2] & ret[j-2] < ret[j-3] ) vola.company[j] = 1
      }

      return(vola.company)

    }


  volatility <- function(ret, nvola)
  {
   length.company = length(ret)
   vola.company = rep(-1, length.company)
   if(length.company < nvola) {
   return(vola.company)
  }
   for(j in 1:(length.company - nvola + 1)) {
   vola.j = ret[j:(j + nvola - 1)]
   vola.company[j + nvola - 1] = sqrt(var(vola.j))
   }
    return(vola.company)
   }

############################################################################


  # 开始构建策略

  
  #data.China = read.table("C:\\R\\Data\\p.txt",header=T)   # 读入原始价格数据
  data.China = read.table("..\\Data\\p.txt",header=T)   # 读入原始价格数据
   
  # dim(data.China)/35
  # data.China[1:40,]

  Stock.date.order = as.Date(rownames(data.China),"%m/%d/%Y")    #提取股票价格日期序列
  
  Volume.China = read.table("..\\Data\\v.txt",header=T)        # 读入原始交易量数据     
  Volume.date.order = as.Date(rownames(Volume.China),"%m/%d/%Y")  # 提取股票交易量日期序列

  data.CSI = read.csv("..\\Data\\CSI300Index6years.csv",header=T)  # 指数序列
  Index.date = as.Date(as.character(data.CSI$Date),"%m/%d/%Y")        #提取指数日期序列

  # data sorting

  Id.temp.stock = as.character(colnames(data.China))        # 股票名称
  Id.order.stock = unique(Id.temp.stock)                    # 股票名称序列
  Id.num.stock = length(Id.order.stock)                     # 股票数量

  Date.length.stock = length(Stock.date.order)
  Date.length = Date.length.stock                           # 股票序列天数

  data.close.spx = as.matrix(data.China)                    # 以矩阵形式存储价格数据
  data.volume.spx = as.matrix(Volume.China)                 # 以矩阵形式存储交易量数据


  # sum(apply(data.close.spx,1,function(x){sum(is.na(x))}) < Id.num.stock)   # 有多少天数据有缺失？大部分！
  
    weekday.sel = match(Index.date,Stock.date.order)                    # 只选择有指数数据的天
  
    data.close.spx = data.close.spx[weekday.sel[!is.na(weekday.sel)],]     # 根据指数数据选取有效价格数据
    data.volume.spx = data.volume.spx[weekday.sel[!is.na(weekday.sel)],]    # 根据指数数据选取有效交易量数据

    Stock.date.order = Stock.date.order[weekday.sel[!is.na(weekday.sel)]]   # 重新定义股票时间序列和天数
    Date.length.stock = length(Stock.date.order)
    Date.length = Date.length.stock 

    data.CSI = data.CSI[!is.na(weekday.sel),]                   # 重新选取有效指数日，保证和股票数据对应

    Index.date = Index.date[!is.na(weekday.sel)]


 # Backfill NA price days 填充缺失数据，目的在于不影响指标的计算

   for ( i in 1 : Id.num.stock )
    {
      for( j in 2 : Date.length )
       {
         if( is.na(data.close.spx[j,i]) & !is.na(data.close.spx[j-1,i]) )
           {
             data.close.spx[j,i] = data.close.spx[j-1,i]
           }       
       }
    }

   # data.close.spx[,i]


 # Get technical factors 一些衍生指标的计算，每个都以单独的矩阵形式存在
   
  data.EMA5.spx = matrix(0, Date.length, Id.num.stock)
  data.EMA12.spx = matrix(0, Date.length, Id.num.stock)

  data.MACD5.spx = matrix(0, Date.length, Id.num.stock)
  data.DIF5.spx = matrix(0, Date.length, Id.num.stock)

  data.RetCC.spx = matrix(0, Date.length, Id.num.stock)

  data.MTM.spx = matrix(0, Date.length, Id.num.stock)
  data.MTMMA12.spx = matrix(0, Date.length, Id.num.stock)

  data.CloseToMA5.spx = matrix(0, Date.length, Id.num.stock)
  data.MA5ToMA12.spx = matrix(0, Date.length, Id.num.stock)

 # i=1
  for( i in 1:Id.num.stock )   # 利用循环计算各项指标并存储

   {
    data.EMA5.spx[,i] = MA(data.close.spx[,i],5)
    data.EMA12.spx[,i] = MA(data.close.spx[,i],12)

    data.DIF5.spx[,i] = data.EMA5.spx[,i] - data.EMA12.spx[,i]
    data.MACD5.spx[,i] = MA(data.DIF5.spx[,i],9)

    data.RetCC.spx[,i] = c(0,diff(data.close.spx[,i])/data.close.spx[1:(Date.length-1),i]*100 )

    data.MTM.spx[,i] = MTM(data.close.spx[,i],10)/data.EMA5.spx[,i]*100
    data.MTMMA12.spx[,i] = c(rep(0,9),MA(data.MTM.spx[10:Date.length,i],12))

    data.CloseToMA5.spx[,i] = (data.close.spx[,i] - data.EMA5.spx[,i])/data.EMA5.spx[,i]*100
    data.MA5ToMA12.spx[,i] = (data.EMA5.spx[,i] - data.EMA12.spx[,i])/data.EMA12.spx[,i]*100

  }

 

  # plot(data.DIF5.spx[,i] - data.MACD5.spx[,i],type="l") # 随手画个图看看，直观监控中间结果！

  
   # 更多的衍生指标
   data.EMA20.spx = apply(data.close.spx,2,function(x){MA(x,20)})          # 移动平均
   data.Vola5.spx = apply(data.RetCC.spx,2,function(x){Volatility(x,5)})     # 收益率的五天波动性
   data.Vola20.spx = apply(data.RetCC.spx,2,function(x){Volatility(x,20)})
   data.Vola5MA5.spx = apply(data.Vola5.spx,2,function(x){MA(x,5)})          # 五天波动性的五天均线
   data.VolumeMA5.spx = apply(data.volume.spx,2,function(x){MA(x,5)})        # 交易量五天均线
   data.VolumeMA10.spx = apply(data.volume.spx,2,function(x){MA(x,10)})
   data.RSI14.spx = apply(data.close.spx,2,function(x){RSI(x,14)})
   data.RSI20.spx = apply(data.close.spx,2,function(x){RSI(x,20)})

   data.SD12.spx = apply(data.close.spx,2,function(x){Volatility(x,12)})    # 价格的12天波动性
   data.SD20.spx = apply(data.close.spx,2,function(x){Volatility(x,20)}) 

   data.ROC12.spx = apply(data.close.spx,2,function(x){ROC(x,12)})
   data.ROC20.spx = apply(data.close.spx,2,function(x){ROC(x,20)})
   data.ROC30.spx = apply(data.close.spx,2,function(x){ROC(x,30)})

   data.StoRSI20.spx = apply(data.RSI20.spx,2,function(x){RSV(x,x,x,20)})
   data.StoRSI20K.spx = apply(data.StoRSI20.spx,2,function(x){MA(x,6)})
   data.StoRSI20D.spx = apply(data.StoRSI20K.spx,2,function(x){MA(x,6)})

   data.DIF12.spx = data.EMA12.spx - data.EMA20.spx
   data.MACD12.spx = apply(data.DIF12.spx,2,function(x){MA(x,9)})

   data.CloseToMA20.spx = (data.close.spx - data.EMA20.spx)/data.close.spx*100


   # 再次随手画个图，随时对你算的东西有个直观印象

   k=100

   par(mfrow=c(2,1))

   plot(data.close.spx[220:Date.length,k],type="l")
   lines(data.EMA5.spx[220:Date.length,k] + data.SD12.spx[220:Date.length,k] ,col="red")
   lines(data.EMA5.spx[220:Date.length,k] - data.SD12.spx[220:Date.length,k] ,col="red")

   plot(data.StoRSI20.spx[220:Date.length,k],type="l")
   lines(data.StoRSI20K.spx[220:Date.length,k],col="red")
   lines(data.StoRSI20D.spx[220:Date.length,k],col="blue")

#################################################

#  利用技术指标的规则产生交易组合


  period.temp = 0
  score.scale = 2
  nsize = 30            # 每天最大交易股票数
  weightstep = 1
  nsizescale = 500
  namount = 40000
  ntradeamount = 20000

  edge.scale = 2
  stoploss.cut = -20
  holding.max = 20    # 最大持有天数
  exit.scale = 2     # parameter used in trailing stop

  size.scale = rep(1,Date.length)

  long.pos = matrix(0,Id.num.stock,Date.length)     # 记录交易信号产生日期的矩阵
  short.pos = matrix(0,Id.num.stock,Date.length) 

  long.keep = matrix(0,Id.num.stock,Date.length)    # 记录股票持仓状态的矩阵
  short.keep = matrix(0,Id.num.stock,Date.length) 

  long.pos.weight = matrix(0,Id.num.stock,Date.length)
  short.pos.weight = matrix(0,Id.num.stock,Date.length) 

  long.pnl = matrix(0,Id.num.stock,Date.length)      # 记录每只股票每天的收益率
  short.pnl = matrix(0,Id.num.stock,Date.length) 

  long.capper = matrix(0,Id.num.stock,Date.length)
  short.capper = matrix(0,Id.num.stock,Date.length) 

  long.Id = matrix(NA,Id.num.stock,Date.length)     # 记录交易股票的名称
  short.Id = matrix(NA,Id.num.stock,Date.length) 

  long.share = matrix(NA,Id.num.stock,Date.length)   # 记录交易股票的股数
  short.share = matrix(NA,Id.num.stock,Date.length) 

  trade.sign = rep(0,Date.length)

  trade.long = rep(0,Date.length)
  trade.short = rep(0,Date.length)

  trade.long.size = rep(0,Date.length)
  trade.short.size = rep(0,Date.length)

  long.pos.daily = rep(0,Date.length)
  short.pos.daily = rep(0,Date.length)
  trade.pos.daily = rep(0,Date.length)

  long.ret.daily = rep(0,Date.length)
  short.ret.daily = rep(0,Date.length)

  long.per.daily = rep(0,Date.length)
  short.per.daily = rep(0,Date.length)

  long.sel = as.numeric(0)  
  short.sel = as.numeric(0) 
  longexit.sel = as.numeric(0)  
  shortexit.sel = as.numeric(0) 

# i=41

  for( i in 16:(Date.length-1) )  #     
  
  { 
     long.current = seq(1:Id.num.stock)[long.keep[,i] == 1]       # 记录当前在持多仓的股票
     short.current = seq(1:Id.num.stock)[short.keep[,i] == -1]    # 记录当前在持空仓的股票
    
     long.keep[long.current,i+1] = 1         # 先假设明天会继续持仓并记入仓位记录矩阵
     short.keep[short.current,i+1] = -1

     long.ini = rep(0,Id.num.stock)      # monitor initial pos for current positions
     short.ini = rep(0,Id.num.stock)

     long.length = rep(0,Id.num.stock)   # monitor holding time for current positions
     short.length = rep(0,Id.num.stock)

     if( length(long.current)==1 ) long.cur = tail(seq(1:(i-1))[diff(long.keep[long.current,1:i])>0],1) + 1 
     if( length(short.current)==1 ) short.cur = tail(seq(1:(i-1))[diff(short.keep[short.current,1:i])<0],1) + 1 

     # 记录当然仓位开始交易的时间
     if( length(long.current)!=1 ) long.cur = apply(long.keep[long.current,1:i],1,function(x){tail(seq(1:(i-1))[diff(x)>0],1)}) + 1 
     if( length(short.current)!=1 ) short.cur = apply(short.keep[short.current,1:i],1,function(x){tail(seq(1:(i-1))[diff(x)<0],1)}) + 1 


     long.ini[long.current] = long.cur      # 将当前仓位开始交易的时间存入
     short.ini[short.current] = short.cur

     long.length[long.current] = i - long.cur + 1     # 记录当前仓位已经持仓的时间长度        
     short.length[short.current] = i - short.cur + 1        

     long.keep[longexit.sel,i+1] = long.keep[longexit.sel,i+1] - 1      # 将今天要平仓的股票在明天的仓位记录归零
     short.keep[shortexit.sel,i+1] = short.keep[shortexit.sel,i+1] + 1

     long.pos[longexit.sel,i] = -1              # 将今天要平仓的股票写入交易矩阵
     short.pos[shortexit.sel,i] = 1

     long.price.temp = data.close.spx[i-1,long.current]    # 当前仓位昨天的收盘价
     short.price.temp = data.close.spx[i-1,short.current]

     long.price.temp[match(long.sel,long.current)] = data.close.spx[i,long.sel]      # 今天刚刚建立的仓位使用今天收盘价作为基准
     short.price.temp[match(short.sel,short.current)] = data.close.spx[i,short.sel]

     long.daily.temp = sum((data.close.spx[i,long.current] - long.price.temp)/long.price.temp*100)   # 今天的单边总收益
     short.daily.temp = sum((data.close.spx[i,short.current] - short.price.temp)/short.price.temp*100) 

     long.per.daily[i] = long.per.daily[i] + mean((data.close.spx[i,long.current] - long.price.temp)/long.price.temp*100)  # 今天的平均收益
     short.per.daily[i] = short.per.daily[i] + mean((data.close.spx[i,short.current] - short.price.temp)/short.price.temp*100)

     long.pnl[long.current,i] = (data.close.spx[i,long.current] - long.price.temp)/long.price.temp*100     # 记录每一只持仓股票在今天的盈亏
     short.pnl[short.current,i] = (data.close.spx[i,short.current] - short.price.temp)/short.price.temp*100

     long.ret.daily[i] = long.ret.daily[i] + long.daily.temp             # 记录每天的百分比总收益
     short.ret.daily[i] = short.ret.daily[i] + short.daily.temp
  
     long.pos.daily[i] = long.pos.daily[i] + length(long.current)      # 记录每天的单边持仓股票数量
     short.pos.daily[i] = short.pos.daily[i] + length(short.current)
     trade.pos.daily[i] = trade.pos.daily[i] + max(length(long.current),length(short.current))
 
 
     # condition to enter the trade

       buy.band = data.EMA20.spx[i,] - edge.scale * data.SD20.spx[i,]     # 定义一个买入的布林带下限
       sell.band = data.EMA20.spx[i,] + edge.scale * data.SD20.spx[i,]    # 定义一个卖出的布林带上限

       short.cond0 = short.keep[,i] != -1   #  不能重复卖空已经在空仓的股票 

     # short.cond1 = data.CloseToMA20.spx[i,] > 5       # 各种可参考的卖空条件
     # short.cond1 = data.close.spx[i,] > sell.band
     # short.cond1 = data.ROC20.spx[i,] > 70 & data.StoRSI20.spx[i,] > 80 & data.RetCC.spx[i,] > 0 & data.RetCC.spx[i-1,] > 0 
     # short.cond1 = (data.DIF5.spx[i,] - data.MACD5.spx[i,])/data.close.spx[i,]*100 > 1 & data.ROC20.spx[i,] > 70
     
        short.cond11 = (data.EMA5.spx[i-3,] - data.EMA12.spx[i-3-12,])/data.EMA12.spx[i-3-12,]*100 < -5   # 卖空子条件之一
        short.cond12 =data.CloseToMA5.spx[i,] > 3 & data.RetCC.spx[i,] > 0 & data.volume.spx[i,] > data.volume.spx[i-1,]  # 卖空子条件之二
        short.cond1 = (short.cond12)  # 组合卖空条件

     #  shortRet.temp = data.CloseToMA20.spx[i,]/data.Vola20.spx[i,]    # 一个利用排序法选择卖空的机制
     #  shortRet.temp = data.StoRSI20D.spx[i,]
     #  shortRet.temp[is.na(shortRet.temp)] = -999
     #  shortRet.sel = order(shortRet.temp)[(length(shortRet.temp)-19):length(shortRet.temp)]      
     #  short.cond1 = rep(FALSE,length(shortRet.temp))
     #  short.cond1[shortRet.sel] = TRUE

       short.cond = short.cond0 & short.cond1  # 最终卖空条件
     
       short.sel = seq(1:Id.num.stock)[short.cond]
       short.sel = short.sel[!is.na(short.sel)]

       long.cond0 = long.keep[,i] != 1 

     # long.cond1 = data.CloseToMA5.spx[i,] < -5 
     # long.cond1 = data.close.spx[i,] < buy.band 
     # long.cond1 = data.ROC20.spx[i,] < 30 & data.StoRSI20.spx[i,] < 20 & data.RetCC.spx[i,] < 0  & data.RetCC.spx[i-1,] < 0  
     # long.cond1 = (data.DIF5.spx[i,] - data.MACD5.spx[i,])/data.close.spx[i,]*100 < -1 & data.ROC20.spx[i,] < 30
 
        long.cond11 = data.close.spx[i,] < buy.band  
        long.cond12 = data.CloseToMA5.spx[i,] < -3 & data.RetCC.spx[i,] < 0 & data.volume.spx[i,] > data.volume.spx[i-1,]  
        long.cond1 = (long.cond12)  

     #  longRet.temp = data.CloseToMA20.spx[i,]/data.Vola20.spx[i,]
     #  longRet.temp = data.StoRSI20D.spx[i,]
     #  longRet.temp[is.na(longRet.temp)] = 999        # mark NAs with high return so to select lowest returns in ranking
     #  longRet.sel = order(longRet.temp)[1:20]      
     #  long.cond1 = rep(FALSE,length(longRet.temp))
     #  long.cond1[longRet.sel] = TRUE

       long.cond = long.cond0 & long.cond1       
 
       long.sel = seq(1:Id.num.stock)[long.cond]
       long.sel = long.sel[!is.na(long.sel)]

        KMAdiff = data.CloseToMA5.spx[i,]   # measure to determine hedge    
        KMAsize = -data.CloseToMA5.spx[i,]   # 定义一个用来限制股票数量的排序原则

     #   capper.temp = namount/data.close.spx[i,]/data.ADV.spx[i,]*100   # 一个流动性检查，供参考
     #   long.sel = long.sel[capper.temp[long.sel] < 0.5 & data.close.spx[i,long.sel] > 3 ]
     #   short.sel = short.sel[capper.temp[short.sel] < 0.5 & data.close.spx[i,short.sel] > 3 ]

     #  if( length(long.sel) == 0 & length(short.sel) == 0 )  next    

        size.max = max(length(long.sel),length(short.sel))     # 记录明天需建仓的最大量
        if( size.max > nsizescale ) size.scale[i] = nsizescale/size.max    # 如果超出最大允许建仓量，则按比例缩小
   
        if( length(long.sel) > nsize ) long.sel = long.sel[ order(KMAsize[long.sel])[(length(long.sel)-nsize+1):length(long.sel)] ]   # 若数量超出限制则按排序原则删减
        if( length(short.sel) > nsize ) short.sel = short.sel[ order(KMAsize[short.sel])[1:nsize] ]

     #  long.weight = rep(1,length(long.sel)); short.weight = rep(1,length(short.sel)) 

        long.pos[long.sel,i] = 1        # 记录信号的产生 
        short.pos[short.sel,i] = -1 

        long.keep[long.sel,i+1] = long.keep[long.sel,i+1] + 1            # 在明天的位置记录仓位
        short.keep[short.sel,i+1] = short.keep[short.sel,i+1] - 1

        trade.sign[i] = 1   
 
      #  long.pos.weight[long.sel,i] = long.weight
      #  short.pos.weight[short.sel,i] = short.weight

        long.Id[long.sel,i] = Id.order.stock[long.sel]           # 记录拟交易股票的ID
        short.Id[short.sel,i] = Id.order.stock[short.sel] 

        long.share[long.sel,i] = round(ntradeamount/data.close.spx[i,long.sel],-2)    # 固定投资额下计算交易股数
        short.share[short.sel,i] = round(ntradeamount/data.close.spx[i,short.sel],-2) 

        trade.long.size[i] = sum(long.share[long.sel,i]*data.close.spx[i,long.sel])
        trade.short.size[i] = sum(short.share[short.sel,i]*data.close.spx[i,short.sel])  # 总交易钱数

        long.accum = rep(0,Id.num.stock)    # 计算累计盈亏
        short.accum = rep(0,Id.num.stock)
        long.trail = rep(0,Id.num.stock)    # 计算跟踪止损点
        short.trail = rep(0,Id.num.stock)

 
        for( j in 1:Id.num.stock)
         {
          if( long.ini[j] > 0 ) long.accum[j] = sum(long.pnl[j,long.ini[j]:i])
          if( short.ini[j] > 0 ) short.accum[j] = sum(short.pnl[j,short.ini[j]:i])
          if( long.ini[j] > 0 ) long.trail[j] = max(data.close.spx[long.ini[j]:i,j])*(1+stoploss.cut/100*(1-long.length[j]/holding.max/exit.scale))
          if( short.ini[j] > 0 ) short.trail[j] = min(data.close.spx[short.ini[j]:i,j])*(1-stoploss.cut/100*(1-short.length[j]/holding.max/exit.scale))
          if( short.pos[j,i] == -1 ) short.trail[j] = min(data.close.spx[i,j])*(1-stoploss.cut/100*(1-short.length[j]/holding.max/exit.scale))
         }


        longexit.stop = data.close.spx[i,] < long.trail    # 需要止损的股票
        longexit.cond0 = long.keep[,i+1] == 1              # 确认正在持仓中
      # longexit.cond1 = data.close.spx[i,] > data.EMA20.spx[i,] + 0.5 * edge.scale * data.SD20.spx[i,]  # 参考退出条件
      # longexit.cond1 = data.CloseToMA20.spx[i,] > 2*data.Vola20.spx[i,]
      # longexit.cond1 = data.StoRSI20D.spx[i,] > 80 & data.ROC20.spx[i,] > 70
      # longexit.cond1 = data.volume.spx[i-1,]/data.VolumeMA5.spx[i-1,] < 1 & data.volume.spx[i,]/data.VolumeMA5.spx[i,] < 1 
        longexit.cond1 = data.close.spx[i,] > data.EMA12.spx[i,] + 150 * data.SD20.spx[i,]   # 按正常条件退出的股票

        longexit.cond = longexit.cond0 & (longexit.stop)
        longexit.sel = seq(1:Id.num.stock)[longexit.cond]
        longexit.sel = longexit.sel[!is.na(longexit.sel)]

        shortexit.stop = data.close.spx[i,] > short.trail
        shortexit.cond0 = short.keep[,i+1] == -1
      # shortexit.cond1 = data.close.spx[i,] < data.EMA20.spx[i,] - 0.5 * edge.scale * data.SD20.spx[i,]
      # shortexit.cond1 = data.CloseToMA20.spx[i,] < -2*data.Vola20.spx[i,]
      # shortexit.cond1 = data.StoRSI20D.spx[i,] < 20 & data.ROC20.spx[i,] < 30
      # shortexit.cond1 = data.volume.spx[i-1,]/data.VolumeMA5.spx[i-1,] < 1 & data.volume.spx[i,]/data.VolumeMA5.spx[i,] < 1 
        shortexit.cond1 = data.close.spx[i,] < data.EMA12.spx[i,] - 150 * data.SD20.spx[i,]

        shortexit.cond =  shortexit.cond0 & ( shortexit.stop)
        shortexit.sel = seq(1:Id.num.stock)[shortexit.cond]
        shortexit.sel = shortexit.sel[!is.na(shortexit.sel)]
        
       }  # i loop

        
  #  trade.long.valid = long.per.daily
  # trade.short.valid = short.per.daily

    long.pnl[is.na(long.pnl)] = 0
    short.pnl[is.na(short.pnl)] = 0


    long.per.valid = long.per.daily     # 确认有效每日收益率序列，仍有无效点，为什么？
    long.per.valid[is.na(long.per.valid)] = 0
    short.per.valid = short.per.daily
    short.per.valid[is.na(short.per.valid)] = 0

    long.ret.valid = apply(long.pnl,2,sum)   # 收益金额序列
    short.ret.valid = apply(short.pnl,2,sum)

    plot(cumsum(long.per.valid),type="l")    # 先画个草图看看我们的成果
    plot(cumsum(long.ret.valid),type="l")



# plot 画个比较正式的图

    par(mfrow=c(1,1))

   pnl.ret.hedge = long.ret.valid   # 选择输入的收益率序列，此处为单边买入收益金额序列

   Sharpe.SPY = mean(pnl.ret.hedge)/sd(pnl.ret.hedge)*sqrt(length(pnl.ret.hedge))
   plot(cumsum(pnl.ret.hedge),type="l",main = "PnL of L/S Stock",xlab="Days",ylab="PnL")
   legend(1,max(cumsum(pnl.ret.hedge)),legend=paste("Sharpe=", round(Sharpe.SPY,2),", Ave.Ret=",round(sum(pnl.ret.hedge)/length(pnl.ret.hedge),1)))

  # plot for a single stock  挑一只个股通过图形研究下买入卖出点

  match("X600271.CH",Id.order.stock)

  k = match("X600271.CH",Id.order.stock)
  trail.seq = 600:900

  par(mfrow=c(2,1))
  
  plot( data.close.spx[trail.seq,k], type="l")  
  lines( data.EMA12.spx[trail.seq,k],col="brown")
  lines( data.EMA12.spx[trail.seq,k] - edge.scale * data.SD20.spx[trail.seq,k], col="red")
  lines( data.EMA12.spx[trail.seq,k] + edge.scale * data.SD20.spx[trail.seq,k], col="red")
  points( seq(1:length(trail.seq))[long.pos[k,trail.seq]==1], (data.close.spx[trail.seq,k])[long.pos[k,trail.seq]==1],col="blue") 
  points( seq(1:length(trail.seq))[long.pos[k,trail.seq]==-1], (data.close.spx[trail.seq,k])[long.pos[k,trail.seq]==-1],col="green") 
 
  barplot(data.volume.spx[trail.seq,k])
  lines(data.VolumeMA5.spx[trail.seq,k],col="red")



####################################################

  # index hedge pnl   鉴于中国市场卖空的困难，让我们用指数对冲

   index.close = data.CSI[,2]
   index.ret = c(0,diff(index.close)/index.close[1:(length(index.close)-1)])*100

   plot(cumsum(index.ret),type="l")

   hedge.per.daily = index.ret
   hedgelong.ret.daily = index.ret*long.pos.daily 
   hedgeshort.ret.daily = index.ret*short.pos.daily 

   long.per.hedged = long.per.valid - hedge.per.daily  # 单边买入用指数对冲后的收益率序列
   long.per.hedged[is.na(long.per.hedged)] = 0

   long.ret.hedged = long.ret.valid - hedgelong.ret.daily  # 单边买入用指数对冲后的收益金额序列
   short.ret.hedged = short.ret.valid - hedgeshort.ret.daily

   short.per.hedged = short.per.valid - hedge.per.daily
   short.per.hedged[is.na(short.per.hedged)] = 0

   plot(cumsum(long.per.hedged),type="l")
   plot(cumsum(short.per.hedged),type="l")

   plot(cumsum(long.ret.hedged),type="l")
   plot(cumsum(short.ret.hedged),type="l")

    long.trade.daily = apply(abs(long.pos),2,sum)  # 计算下简单的交易成本
    trans.ret.long.daily = long.trade.daily*0.12   # 假设单边交易12个基点的成本
    short.trade.daily = apply(abs(short.pos),2,sum)
    trans.ret.short.daily = short.trade.daily*0.12

    pnl.ret.hedge = long.ret.hedged - trans.ret.long.daily
  # pnl.ret.hedge = short.ret.hedged - trans.ret.short.daily
  # pnl.ret.hedge = long.ret.hedged - trans.ret.long.daily - (short.ret.hedged - trans.ret.short.daily)
  # pnl.ret.hedge = (long.ret.hedged - trans.ret.long.daily)/long.pos.daily

   pnl.ret.hedge[is.na(pnl.ret.hedge) | pnl.ret.hedge == -Inf ] = 0

   # Plot pnl and position in the same graph  画个综合的图

   Sharpe.SPY = mean(pnl.ret.hedge)/sd(pnl.ret.hedge)*sqrt(length(pnl.ret.hedge))
   plot(cumsum(pnl.ret.hedge),type="l",main = "PnL of Long Stock/Short Index",xlab="Days",ylab="PnL")
   legend(300,max(cumsum(pnl.ret.hedge)),legend=paste("Sharpe=", round(Sharpe.SPY,2),", Ave. Daily Ret=",round(sum(pnl.ret.hedge)/length(pnl.ret.hedge),2)))

   par(new=TRUE)
   plot(long.pos.daily + short.pos.daily,,type="l",col="blue",xaxt="n",yaxt="n",xlab="",ylab="")
   axis(4)
   mtext("Position",side=4,line=3)
   legend("topleft",col=c("black","blue"),lty=1,legend=c("Pnl","Position"))


   sum(abs(long.pos))/Date.length
   mean(long.pos.daily)
   mean(trade.period)

   sum(abs(short.pos))/Date.length
   mean(short.pos.daily)

# 以上整个过程中，出现最多的词是什么？记录！



